/*
 * Middleware
 * Copyright (C) 2010/11
 * Riccardo Pulvirenti, Giuseppe Ravidà, Andrea Tino
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses
 */

/*!
 * File: task_descriptor_test.hpp
 */

#ifndef _TASK_DESCRIPTOR_TEST_HPP_
#define _TASK_DESCRIPTOR_TEST_HPP_

#include <iostream>
#include <sstream>
#include "task_descriptor.hpp"
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

//-----------------------------------------------------------------------------
#define MODE_SERVER
//-----------------------------------------------------------------------------

using namespace std;
using boost::asio::ip::tcp;

namespace middleware {
//-----------------------------------------------------------------------------
// Definitions
/*!
 * Test function for TaskDescriptor
 */
void TaskDescriptorTest();
void TaskDescriptorSerializationTest();
void TaskDescriptorTCPSerializationTest();
//-----------------------------------------------------------------------------
// Implementations
void TaskDescriptorSerializationTest() {
	stringstream ss (stringstream::in | stringstream::out);

	TaskDescriptor task;
	{
		boost::archive::text_oarchive oa(ss);
		task.set_id(10);
		oa<<task;
	}

	TaskDescriptor newTask;
	{
		// create and open an archive for input
		boost::archive::text_iarchive ia(ss);
		// read class state from archive
		ia >> newTask;
		// archive and stream closed when destructors are called
	}

	cout << "Serialization test.If this print " << task.get_id() << ",it works:"
			<< newTask.get_id() << std::endl;
}

void TaskDescriptorTest() {
	TaskLinkage in_link;
	TaskLinkage out_link;
	out_link.machine_addr = "link1";
	out_link.network_inet_ip = "link2";
	out_link.network_inet_port = "link3";
	/*!
	 * Testing the default constructor
	 */
	TaskDescriptor t1;
	/*!
	 * Testing an executable task
	 */
	TaskDescriptor t2(kTaskExecutable, "command 2");
	/*!
	 * Testing a command task
	 */
	TaskDescriptor t3(kTaskExecutable, "link 3");
	/*!
	 * Testing copy constructor
	 */
	TaskDescriptor t4;
	t4 = t3;
	/*!
	 * Testing set_id()
	 */
	t1.set_id(10);
	/*!
	 * Testing get_id()
	 */
	cout << t1.get_id() << std::endl;
	/*!
	 * Testing set_type()
	 */
	t1.set_type(kTaskBashCommand);
	/*!
	 * Testing get_type()
	 */
	cout << t1.get_type() << std::endl;
	/*!
	 * Testing set_link()
	 */
	t1.set_link(out_link);
	/*!
	 * Testing get_link()
	 */
	in_link = t1.get_link();
	cout << in_link.machine_addr << " " << in_link.network_inet_ip << " " << 
			in_link.network_inet_port << std::endl;
	/*!
	 * Testing set_command()
	 */
	t1.set_command("comando1");
	/*!
	 * Testing get_command()
	 */
	cout << t1.get_command() << std::endl;
	/*!
	 * Testing getInvalidTaskDescriptor()
	 */
	cout << TaskDescriptor::getInvalidTaskDescriptor().get_id() << std::endl;
	cout << "Testing Copy Constructor..." << std::endl;
	t4.set_id(40);
	cout << "Copy Constructor ID:" << t4.get_id() << std::endl;
	t3.set_id(30);
	cout << "Copy Constructor ID after changing t3:" << t4.get_id() <<
			std::endl;
}
void TaskDescriptorTCPSerializationTest(){

	#ifdef MODE_SERVER
		// Server
		try {
			TaskDescriptor newTs;

			boost::asio::io_service io_s; /* Create an io_service */
			boost::asio::ip::tcp::acceptor acc(io_s,
					boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),
							1950)); /* Configure acceptor */
			tcp::iostream stream; /* Define a stream */
			acc.accept(*stream.rdbuf()); /* Accept and get the rdbuf in the request and let my buffer point to it */

			for (;;) {
				cout << "-1-" << endl;
				boost::archive::binary_iarchive ia(stream);
				cout << "-2-" << endl;
				ia >> newTs;

				std::cout << "Task ID: " << newTs.get_id() << std::endl;
				stream << "Grazie!" << std::endl;
			}

		} catch(std::exception& e) {
			std::cout << e.what() << std::endl;
		}
	#else
		// Client
		try {

			TaskDescriptor task1;

			task1.set_id(10);

			tcp::iostream stream("127.0.0.1", "1950"); // Creates stream ALREADY BINDED TO AN INET ADDR
			std::string command; /* I should receive and send commands */
			if (!stream) {
				throw std::runtime_error("Could not connect!");
			} else {
				for (;;) {
					boost::archive::binary_oarchive oa(stream);
					oa << task1;

					cout << task1.get_id() << endl;

					if (std::getline(stream, command)) std::cout << "Server: " << command << std::endl; /* Line approach for receiving */
					boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
				}
			}

		} catch(std::exception& e) {
			std::cout << e.what() << std::endl;
		}
#endif
}

} /* middleware */
#endif
